package felix.things.router.modbus.net;

import com.ghgande.j2mod.modbus.io.AbstractModbusTransport;
import com.ghgande.j2mod.modbus.io.ModbusUDPTransport;
import com.ghgande.j2mod.modbus.net.AbstractUDPTerminal;
import felix.things.router.modbus.transport.UdpTransportConfiguration;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * @author Felix
 * @date 2019/10/30
 **/
@Component
@Slf4j
public class UdpModbusMasterFactory {

    public static AbstractModbusTransport createModbusTransport(UdpTransportConfiguration transportConfiguration) {
        /*
         * Create a ModbusUDPListener with the default interface value. The
         * second optional value is the TCP port number and the third
         * optional value is the Modbus unit number.
         */
        AbstractUDPTerminal terminal = null;
        try {
            int currentPort = transportConfiguration.getPort();
            InetAddress currentAddress = InetAddress.getByName(transportConfiguration.getHost());
            // terminal = new UDPMasterTerminal(InetAddress.getByName(hostName));
            terminal = new AbstractUDPTerminal() {
                @Override
                public void activate() throws Exception {
                    if (!this.isActive()) {
                        if (this.socket == null) {
                            this.socket = new DatagramSocket();
                        }

                        log.debug("UDPMasterTerminal::haveSocket():{}", this.socket.toString());
                        log.debug("UDPMasterTerminal::raddr=:{}:rport:{}", currentAddress, currentPort);
                        this.socket.setReceiveBufferSize(transportConfiguration.getReceiveBufferSize());
                        this.socket.setSendBufferSize(transportConfiguration.getSendBufferSize());
                        this.socket.setSoTimeout(transportConfiguration.getTimeout());
                        this.transport = new ModbusUDPTransport(this);
                        this.active = true;
                    }

                    log.debug("UDPMasterTerminal::activated");
                }

                @Override
                public void deactivate() {
                    try {
                        log.debug("UDPMasterTerminal::deactivate()");
                        if (this.socket != null) {
                            this.socket.close();
                        }

                        this.transport = null;
                        this.active = false;
                    } catch (Exception var2) {
                        log.error("Error closing socket", var2);
                    }
                }

                @Override
                public void sendMessage(byte[] msg) throws Exception {
                    DatagramPacket req = new DatagramPacket(msg, msg.length, currentAddress, currentPort);
                    this.socket.send(req);
                }

                @Override
                public byte[] receiveMessage() throws Exception {
                    byte[] buffer = new byte[262];
                    DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
                    this.socket.setSoTimeout(transportConfiguration.getTimeout());
                    this.socket.receive(packet);
                    return buffer;
                }
            };
            terminal.activate();
        } catch (UnknownHostException e) {
            e.printStackTrace();
            return null;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return terminal.getTransport();
    }
}
